
#pragma once
#include "Common/Definitions.h"

#include "Common/Math.h"
#include "Runtime.Low/Threads.h"

#include "ParameterInfo.h"

using namespace System::ComponentModel;

namespace ttg_internal
{
	namespace utils
	{
		//Definition of used class.
		ref class ParameterSet;
		///<summary>
		/// Internal class, that contains real value and some routines.
		/// Can be accessed by .NET utility and owner *.exe (via export functions).
		///</summary>
		public ref class Parameter :public INotifyPropertyChanged,
									public System::IDisposable
		{
			private:
				ParameterSet ^_owner;
				ParameterInfo ^_info;
				System::String ^value;
				System::String ^buffer;
				System::String ^name;
				System::String ^_depPropertyName;
				bool should_apply;
				bool was_modified;
				bool is_locked;
				bool is_read_only;
				ttg::threads::FastCriticalSection *locker;
				ttg::math::uint64 _tag;
			internal:
				Parameter(System::String ^name,
						  ParameterInfo ^info,
						  ParameterSet ^owner,
						  System::String ^depPropertyName);
				///<summary>
				/// Auxiliary tag, that is used for ID storing;
				///</summary>
				property ttg::math::uint64 Tag
				{
					ttg::math::uint64 get()
					{ return _tag; }
					void set(ttg::math::uint64 value)
					{ _tag = value; }
				}
				///<summary>
				/// Notifies about property change.
				///</summary>
				void onPropertyChange(System::String ^name)
				{
					PropertyChanged(this, gcnew PropertyChangedEventArgs(name));
				}
				///<summary>
				/// Internal version of value getting, that [optionally] skips "was_modified" flag.
				///</summary>
				System::String ^ValueGet(bool should_skip);
				///<summary>
				/// Internal version of value setting.
				///</summary>
				void ValueSet(System::String ^value);
			public:
				///<summary>
				/// Event for INotifyPropertChanged.
				///</summary>
				virtual event PropertyChangedEventHandler ^PropertyChanged;
				///<summary>
				/// Returns name of current parameter.
				///</summary>
				property System::String ^Name
				{
					System::String ^get()
					{ return name; }
				}
				///<summary>
				/// Returns owner set of current parameter (or nullptr).
				///</summary>
				property ParameterSet ^Owner
				{
					ParameterSet ^get()
					{ return _owner; }
				}
				///<summary>
				/// Returns additional information about parameter.
				///</summary>
				property ParameterInfo ^Info
				{
					 ParameterInfo ^get()
					 { return _info; }
				}
				///<summary>
				/// get(): returns current value and skips "was_modified" flag.
				/// set(): tries to set new value.
				///		   If parameter is locked, the value will be setted after unlocking.
				///<summary>
				property System::String ^Value
				{
					System::String ^get()
					{ return ValueGet(false); }
					void set(System::String ^value)
					{
						if (!ReadOnly)
							ValueSet(value);
					}
				}
				///<summary>
				/// Sets value for ReadOnly flag.
				///</summary>
				property bool ReadOnly
				{
					public:
						bool get()
						{ return is_read_only; }
					internal:
						void set(bool value)
						{ is_read_only = true; onPropertyChange("ReadOnly"); }
				}
				///<summary>
				/// Locks parameter (after locking it cannot be changed).
				///</summary>
				void lock();
				///<summary>
				/// UnLocks parameters and (optionally) assigns it to new value.
				///</summary>
				void unLock();
				///<summary>
				/// Returns true, if parameter value wasn't modified since last "get()".
				///</summary>
				bool wasModified();
				!Parameter()
				{ SAFE_DELETE(locker); }
				~Parameter()
				{ SAFE_DELETE(locker); }
		};
	}
}
